/**
 * 
 */
package ro.dta.idbi.ui;

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;

import ro.dta.idbi.interfaces.ui.IMainFrame;
import ro.dta.idbi.model.RelationshipDiscovery;
import uk.ac.ic.doc.automed.NotFoundException;
import uk.ac.ic.doc.automed.matching.SchemaElementPairRelationship;
import uk.ac.ic.doc.automed.reps.Schema;

/**
 * User interface for the schema matching tool, that uses the schema maching
 * component in AutoMed
 * 
 * @author Tudor Dobrila
 * 
 */
public class MatchingTool extends JFrame implements ActionListener {

	private static final long serialVersionUID = -7889638536503885937L;

	/**
	 * Button used to start the computation
	 */
	private JButton matchBtn;

	/**
	 * Model of the table holding the results
	 */
	private DefaultTableModel resultsModel;

	/**
	 * Worker thread used to discover the relationships
	 */
	private SemanticWorker worker;

	/**
	 * Schema chooser used to select the first schema
	 */
	private SchemaChooserPanel schemaChooser1;

	/**
	 * Schema chooser used to select the first schema
	 */
	private SchemaChooserPanel schemaChooser2;

	/**
	 * Matching tool class constructor
	 * 
	 * @param parentFrame
	 *            Parent frame of the application
	 */
	public MatchingTool(IMainFrame parentFrame) {
		this(parentFrame, null, null);
	}

	/**
	 * Matching tool class constructor
	 * 
	 * @param parentFrame
	 *            Parent frame of the application
	 * @param schema1
	 *            Name of first schema in the schema pair
	 * @param schema2
	 *            Name of second schema in the schema pair
	 */
	public MatchingTool(IMainFrame parentFrame, String schema1, String schema2) {
		setSize(650, 500);
		setTitle("Semantic relationship discovery tool");
		setLocationRelativeTo(null);
		setIconImage(parentFrame.getIconImage());

		JPanel centerPanel = new JGradientPanel(new GridBagLayout());
		getContentPane().add(centerPanel, BorderLayout.CENTER);

		GridBagConstraints constr = new GridBagConstraints();
		constr.fill = GridBagConstraints.BOTH;

		constr.gridwidth = 2;
		constr.gridx = 0;
		constr.gridy = 0;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		constr.ipady = 20;
		centerPanel.add(parentFrame.getGuiFactory().createTitleLabel("Select schemas"), constr);

		constr.gridwidth = 1;
		constr.gridx = 0;
		constr.gridy = 1;
		constr.weightx = 0.4;
		constr.weighty = 0.0;
		constr.ipady = 0;
		JLabel schema1Lbl = new JLabel("Schema 1 :");
		schema1Lbl.setOpaque(false);
		centerPanel.add(schema1Lbl, constr);

		constr.gridx = 1;
		constr.gridy = 1;
		constr.weightx = 0.6;
		constr.weighty = 0.0;
		schemaChooser1 = new SchemaChooserPanel(schema1);
		centerPanel.add(schemaChooser1, constr);

		constr.gridx = 0;
		constr.gridy = 2;
		constr.weightx = 0.4;
		constr.weighty = 0.0;
		constr.ipady = 0;
		centerPanel.add(new JLabel("Schema 2 :"), constr);

		constr.gridx = 1;
		constr.gridy = 2;
		constr.weightx = 0.6;
		constr.weighty = 0.0;
		schemaChooser2 = new SchemaChooserPanel(schema2);
		centerPanel.add(schemaChooser2, constr);

		constr.fill = GridBagConstraints.NONE;
		constr.gridwidth = 2;
		constr.gridx = 0;
		constr.gridy = 3;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		matchBtn = new JButton("Compute correspondences");
		matchBtn.addActionListener(this);
		centerPanel.add(matchBtn, constr);

		constr.fill = GridBagConstraints.BOTH;
		constr.gridx = 0;
		constr.gridy = 4;
		constr.weightx = 1.0;
		constr.weighty = 0.0;
		constr.ipady = 20;
		centerPanel.add(parentFrame.getGuiFactory().createTitleLabel("Semantic relations"), constr);

		constr.gridx = 0;
		constr.gridy = 5;
		constr.weightx = 1.0;
		constr.weighty = 1.0;
		constr.ipady = 0;
		resultsModel = new DefaultTableModel();
		resultsModel.setColumnCount(3);
		resultsModel.setColumnIdentifiers(new String[] { "Object in first schema",
				"Object in second schema", "Relationship" });
		JTable corespTable = new JTable(resultsModel);
		centerPanel.add(new JScrollPane(corespTable), constr);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		matchBtn.setEnabled(false);
		String schema1 = schemaChooser1.getSelectedItem();
		String schema2 = schemaChooser2.getSelectedItem();
		if (schema1.equals(schema2)) {
			JOptionPane.showMessageDialog(
					MatchingTool.this,
					"Please select two different schemas.", "Error!", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		try {
			if (worker != null && !worker.isDone() && !worker.isCancelled()) {
				worker.cancel(true);
			}
			worker = new SemanticWorker(schema1, schema2);
			worker.execute();
		} catch (NotFoundException e1) {
			JOptionPane.showMessageDialog(
					MatchingTool.this,
					"Schema could not be found in the AutoMed repository. Reason:\r\n"
							+ e1.getMessage(), "Error!", JOptionPane.ERROR_MESSAGE);
			return;
		}
	}

	/**
	 * Semantic worker, used to discover semantic relationships between two
	 * schemas on a separate worker thread
	 * 
	 * @author Tudor Dobrila
	 * 
	 */
	class SemanticWorker extends SwingWorker<SchemaElementPairRelationship[], Void> {

		/**
		 * Name of the first schema
		 */
		private final String schema1;

		/**
		 * Name of the second schema
		 */
		private final String schema2;

		/**
		 * Semantic discovery worker thread class constructor
		 * 
		 * @param schema1
		 *            Name of the first schema
		 * @param schema2
		 *            Name of the second schema
		 * @throws NotFoundException
		 *             If one of the schemas does not exist in the AutoMed
		 *             repository
		 */
		public SemanticWorker(String schema1, String schema2) throws NotFoundException {
			this.schema1 = schema1;
			this.schema2 = schema2;

		}

		@Override
		protected SchemaElementPairRelationship[] doInBackground() throws Exception {
			RelationshipDiscovery discovery = new RelationshipDiscovery(Schema.getSchema(schema1),
					Schema.getSchema(schema2));
			return discovery.discoverRelationships();
		}

		@Override
		protected void done() {
			super.done();

			matchBtn.setEnabled(true);
			SchemaElementPairRelationship[] rels;
			try {
				rels = get();
				resultsModel.setNumRows(0);
				resultsModel.setNumRows(rels.length);

				for (int i = 0; i < rels.length; i++) {
					SchemaElementPairRelationship crtRel = rels[i];
					resultsModel.setValueAt(crtRel.getFirstElement(), i, 0);
					resultsModel.setValueAt(crtRel.getSecondElement(), i, 1);
					resultsModel.setValueAt(crtRel.getRelationship(), i, 2);
				}
			} catch (Exception e) {
				JOptionPane.showMessageDialog(
						MatchingTool.this,
						"Could not retrieve the semantic relationships. Reason:\r\n"
								+ e.getMessage(), "Error!", JOptionPane.ERROR_MESSAGE);
			}
		}
	}

}
